package com.joymart.qualification.service;

import com.joymart.common.model.Range;
import com.joymart.common.system.BusinessConfig;
import com.joymart.common.utils.DatetimeUtils;
import com.joymart.compute.service.MonthlyGroupPvService;
import com.joymart.compute.service.SalesPvService;
import com.joymart.qualification.model.AdvanceEvaluation;
import com.joymart.user.model.BusinessRole;
import com.joymart.user.model.CachedUser;
import com.joymart.user.repo.BusinessRoleRepository;
import com.joymart.user.service.UserCacheManager;
import com.joymart.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.MathContext;
import java.util.List;
import java.util.Optional;

@Slf4j
@Service
public class AdvanceEvaluationService {

    @Autowired
    private UserCacheManager userCacheManager;
    @Autowired
    private SalesPvService salesPvService;
    @Autowired
    private BusinessConfig businessConfig;
    @Autowired
    private MonthlyGroupPvService monthlyGroupPvService;
    @Autowired
    private AdvanceEvaluationPersistingService advanceEvaluationPersistingService;
    @Autowired
    private BusinessRoleRepository businessRoleRepository;
    @Autowired
    private UserService userService;

    /**
     * @param range 考察区间
     * @param targetRole 目标角色
     * @return
     */
    public AdvanceEvaluation evaluate(String userId,
                                      Range range,
                                      BusinessRole targetRole) {
        CachedUser user = userCacheManager.get(userId);
        AdvanceEvaluation evaluation = buildEvaluation(user, range, targetRole);
        evaluatePv(evaluation);
        evaluateStructure(evaluation);
        return evaluation;
    }

    public void evaluate(String id, Range range) {
        CachedUser user = userCacheManager.get(id);
        AdvanceEvaluation evaluation = this.evaluate(id, range, user.getHighestRole().next());
        advanceEvaluationPersistingService.save(evaluation);
    }

    private AdvanceEvaluation buildEvaluation(CachedUser user, Range range, BusinessRole targetRole) {
        AdvanceEvaluation evaluation = new AdvanceEvaluation();
        evaluation.setRange(range);
        evaluation.setTargetRole(targetRole);
        evaluation.setUserId(user.getId());
        evaluation.setEvaluateUser(user);
        evaluation.setGroupPv(BigDecimal.ZERO);
        evaluation.setSuperSupported(false);
        evaluation.setCreatedAt(DatetimeUtils.now());

        switch (targetRole){
            case AU_SHOP -> {
                evaluation.setGroupPvSpec(BigDecimal.ZERO); //金店铺无业绩要求
                evaluation.setPrimaryStructureDescription("所需银店铺");
                evaluation.setPrimaryStructurePredicate(cachedUser -> cachedUser.getBusinessRoles().contains(BusinessRole.AG_SHOP));
                evaluation.setPrimaryStructureSpec(1);
                evaluation.setSecondaryStructurePredicate(null);
            }
            case AG_WHS -> {
                evaluation.setGroupPvSpec(businessConfig.getWhsPvSpec());
                evaluation.setPrimaryStructureDescription("所需金店铺");
                evaluation.setPrimaryStructurePredicate(cachedUser -> cachedUser.getBusinessRoles().contains(BusinessRole.AU_SHOP));
                evaluation.setPrimaryStructureSpec(5);
                evaluation.setSecondaryStructurePredicate(null);
            }
            case AU_WHS -> {
                evaluation.setGroupPvSpec(BigDecimal.ZERO); //金批发无业绩要求
                evaluation.setPrimaryStructureDescription("所需银批发");
                evaluation.setPrimaryStructurePredicate(cachedUser -> cachedUser.getBusinessRoles().contains(BusinessRole.AG_WHS));
                evaluation.setPrimaryStructureSpec(1);
                evaluation.setSecondaryStructurePredicate(null);
            }
            case AG_AGENT -> {
                evaluation.setGroupPvSpec(businessConfig.getAgentPvSpec());
                evaluation.setPrimaryStructureDescription("所需金批发");
                evaluation.setPrimaryStructurePredicate(cachedUser -> cachedUser.getBusinessRoles().contains(BusinessRole.AU_WHS));
                evaluation.setPrimaryStructureSpec(5);
                evaluation.setSecondaryStructurePredicate(null);
            }
            case AU_AGENT -> {
                evaluation.setGroupPvSpec(BigDecimal.ZERO);  //金代理无业绩要求
                evaluation.setPrimaryStructureDescription("所需银代理");
                evaluation.setPrimaryStructurePredicate(cachedUser -> cachedUser.getBusinessRoles().contains(BusinessRole.AG_AGENT));
                evaluation.setPrimaryStructureSpec(1);
                evaluation.setSecondaryStructurePredicate(null);
            }
            case MANAGER -> {
                evaluation.setGroupPvSpec(BigDecimal.ZERO);  // 经理无业绩要求
                evaluation.setPrimaryStructureDescription("横排代理业绩达标5个月");
                evaluation.setPrimaryStructurePredicate(cachedUser ->
                        monthlyGroupPvService.countMonthlyGroupPvGreaterThan(cachedUser,
                                BusinessRole.AG_AGENT, evaluation.getRange(),businessConfig.getAgentPvSpec())>=5);
                evaluation.setPrimaryStructureSpec(5);
                evaluation.setSecondaryStructurePredicate(null);
            }
            case AG_DIRECTOR -> {
                evaluation.setGroupPvSpec(BigDecimal.ZERO);  // 总监无业绩要求
                evaluation.setPrimaryStructureDescription("横排经理");
                evaluation.setPrimaryStructurePredicate(cachedUser -> cachedUser.getBusinessRoles().contains(BusinessRole.MANAGER));
                evaluation.setPrimaryStructureSpec(1);
                evaluation.setSecondaryStructureDescription("代理业绩达标10个月");
                evaluation.setSecondaryStructurePredicate(cachedUser ->
                        monthlyGroupPvService.countMonthlyGroupPvGreaterThan(cachedUser,
                                BusinessRole.AG_AGENT, evaluation.getRange(),businessConfig.getAgentPvSpec())>=10);
                evaluation.setSecondaryStructureSpec(5);
            }
            case AU_DIRECTOR -> {
                evaluation.setGroupPvSpec(BigDecimal.ZERO);  // 经理无业绩要求
                evaluation.setPrimaryStructureDescription("横排总监");
                evaluation.setPrimaryStructurePredicate(cachedUser -> cachedUser.getBusinessRoles().contains(BusinessRole.AG_DIRECTOR));
                evaluation.setPrimaryStructureSpec(1);
                evaluation.setSecondaryStructureDescription("横排经理");
                evaluation.setSecondaryStructurePredicate(cachedUser -> cachedUser.getBusinessRoles().contains(BusinessRole.MANAGER));
                evaluation.setSecondaryStructureSpec(5);

            }
        }
        return evaluation;
    }

    /**
     * 评估业绩， 只要达标了就不会继续计算
     * @param evaluation
     */
    private void evaluatePv(AdvanceEvaluation evaluation){
        if(evaluation.getGroupPvSpec() == null ||evaluation.getGroupPvSpec().compareTo(BigDecimal.ZERO) <= 0){
            return;
        }
        CachedUser user = Optional.ofNullable(evaluation.getUserId()).map(userCacheManager::get).orElse(null);
        CachedUser superSupportedUser = userCacheManager
                .downwardsSearchUntil(user, cu -> cu.getBusinessRoles().contains(evaluation.getTargetRole()));
        if(superSupportedUser != null){
            log.info("Super supported user found {}", superSupportedUser);
            evaluation.setSuperSupported(true);
            evaluation.setGroupPvSpec(evaluation.getGroupPvSpec().multiply(new BigDecimal(0.5), MathContext.DECIMAL64));
        }

        collectPv(evaluation, user);
    }


    /**
     * 评估结构，只要达标了就不会继续计算
     * @param evaluation
     */
    private void evaluateStructure(AdvanceEvaluation evaluation) {
        CachedUser user = Optional.ofNullable(evaluation.getUserId()).map(userCacheManager::get).orElse(null);
        List<String> downstreamIds = user.getDownstreamIds();
        for (String downstreamId : downstreamIds) {
            CachedUser downStream = userCacheManager.get(downstreamId);
            if (!evaluation.isPrimaryStructurePassed()) {
                CachedUser primaryMatchedUser = userCacheManager.downwardsSearchUntil(downStream, evaluation.getPrimaryStructurePredicate(), true);
                if (primaryMatchedUser != null) {
                    log.debug("Primary Matched User found : {}", primaryMatchedUser);
                    evaluation.setPrimaryStructureMatched(evaluation.getPrimaryStructureMatched() + 1);
                }
            }

            if (!evaluation.isSecondaryStructurePassed()) {
                CachedUser secondaryMatchedUser = userCacheManager.downwardsSearchUntil(downStream, evaluation.getSecondaryStructurePredicate(), true);
                if (secondaryMatchedUser != null) {
                    log.debug("Secondary Matched User found : {}", secondaryMatchedUser);
                    evaluation.setSecondaryStructureMatched(evaluation.getSecondaryStructureMatched() + 1);
                }
            }

            if(evaluation.isSecondaryStructurePassed()&& evaluation.isPrimaryStructurePassed()){
                break;
            }
        }
    }

    /**
     * @param evaluation
     * @param user 需要收集PV的用户， 在递归起点时，就是接受评估的用户。
     */
    private void collectPv(AdvanceEvaluation evaluation, CachedUser user) {
        //达标后不继续递归计算
        if(evaluation.isPvPassed()){
            return;
        }

        if(evaluation.getCollectPvScale() == null){
            log.warn("No collecting pv is needed for evaluating Role {}, please check logic mistakes", evaluation.getTargetRole());
            return;
        }

        BigDecimal salesPv = salesPvService.getSalesPv(user.getId(), evaluation.getRange());
        evaluation.setGroupPv(evaluation.getGroupPv().add(salesPv, MathContext.DECIMAL64));
        List<String> downstreamIds = user.getDownstreamIds();


        downstreamIds.forEach(downstreamId -> {
            CachedUser downStream = userCacheManager.get(downstreamId);
            // 只计算小部门的 包含了统计粒度 则是大部门
            if(!downStream.getBusinessRoles().contains(evaluation.getCollectPvScale())){
                collectPv(evaluation, downStream);
            }
        });
    }


    /**
     * 重新按照区间评估 总监和董事
     * 年度任务的时候调用
     * @param range
     */
    public void reevaluateAllDirectors(Range range) {
        //先统一降级成经理
        businessRoleRepository.findByBusinessRole(BusinessRole.AG_DIRECTOR)
                .stream()
                .map(userCacheManager::get)
                .map(CachedUser::getUser)
                .forEach(user -> userService.modifyHighestRole(user, BusinessRole.MANAGER));

        this.evaluateAllAgDirectors(range);
        this.evaluateAllAuDirectors(range);




    }

    private void evaluateAllAuDirectors(Range range) {
        List<AdvanceEvaluation> auEvaluations = businessRoleRepository.findByBusinessRole(BusinessRole.AG_DIRECTOR)
                .stream()
                .map(userCacheManager::get)
                .map(user -> evaluate(user.getId(), range, BusinessRole.AU_DIRECTOR)).toList();
        // 不能一个stream下来， 边评估边变化身份 不安全
        auEvaluations.stream().filter(AdvanceEvaluation::isPassed)
                .map(AdvanceEvaluation::getEvaluateUser)
                .map(CachedUser::getUser)
                .forEach(user -> userService.modifyHighestRole(user, BusinessRole.AU_DIRECTOR));
    }

    private void evaluateAllAgDirectors(Range range) {
        List<AdvanceEvaluation> agEvaluations = businessRoleRepository.findByBusinessRole(BusinessRole.MANAGER)
                .stream()
                .map(userCacheManager::get)
                .map(user -> evaluate(user.getId(), range, BusinessRole.AG_DIRECTOR)).toList();
        // 不能一个stream下来， 边评估边变化身份 不安全
        agEvaluations.stream().filter(AdvanceEvaluation::isPassed)
                .map(AdvanceEvaluation::getEvaluateUser)
                .map(CachedUser::getUser)
                .forEach(user -> userService.modifyHighestRole(user, BusinessRole.AG_DIRECTOR));
    }
}
